package com.jrx.anytxn.transaction.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.jrx.anytxn.common.constant.CommonContants;
import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.common.uitl.SeqUtils;
import com.jrx.anytxn.common.uitl.StringUtils;
import com.jrx.anytxn.customer.constant.BankCardConstant;
import com.jrx.anytxn.customer.constant.CustomerConstant;
import com.jrx.anytxn.customer.constant.CustomerConstant;
import com.jrx.anytxn.customer.dto.customer.CustomerRes;
import com.jrx.anytxn.customer.entity.CmCustomerBankcardInfo;
import com.jrx.anytxn.feign.common.GateWayPredicate;
import com.jrx.anytxn.feign.gateway.bean.ApiResponse;
import com.jrx.anytxn.feign.gateway.response.CoreResponse16;
import com.jrx.anytxn.feign.gateway.response.CoreResponse17;
import com.jrx.anytxn.feign.gateway.response.PaymentResponse06;
import com.jrx.anytxn.feign.gateway.service.IInnerGatewayService;
import com.jrx.anytxn.i18n.response.TxnPage;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.constant.Constant;
import com.jrx.anytxn.param.entity.PrAutoPaymentTable;
import com.jrx.anytxn.param.entity.PrOrganizationTable;
import com.jrx.anytxn.param.entity.PrProductTable;
import com.jrx.anytxn.param.service.system.IOrganizationTableService;
import com.jrx.anytxn.param.service.system.ISystemParameterService;
import com.jrx.anytxn.ribbon.config.GrayVersionConfig;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.dto.common.CommonReq;
import com.jrx.anytxn.transaction.dto.transactionLog.TlPaymentLogRes;
import com.jrx.anytxn.transaction.entity.BtAutoPaymentList;
import com.jrx.anytxn.transaction.entity.TlPaymentLog;
import com.jrx.anytxn.transaction.entity.TlPaymentMapping;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlPaymentLogMapper;
import com.jrx.anytxn.transaction.service.IDealGatewayService;
import com.jrx.anytxn.transaction.service.IPaymentLogService;
import com.jrx.anytxn.param.service.system.ISequenceNumberService;
import com.jrx.anytxn.transaction.service.ISmsService;
import com.jrx.anytxn.transaction.utils.PaymentUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * 还款流水service实现
 *
 * @author : zhenghaopu
 * 2019/10/21
 */
@Service
public class PaymentLogServiceImpl implements IPaymentLogService {

    private static final Logger logger= LoggerFactory.getLogger(PaymentLogServiceImpl.class);

    @Autowired
    private ISegmentService segmentService;
    @Lazy
    @Autowired
    private IInnerGatewayService innerGatewayService;
    @Autowired
    private IOrganizationTableService organizationTableService;
    @Autowired
    private IDealGatewayService dealGatewayService;
    @Autowired
    private ISmsService iSmsService;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Resource
    private ExtTlPaymentLogMapper extTlPaymentLogMapper;
    @Autowired
    private ISystemParameterService systemParameterService;
    @Autowired
    private GrayVersionConfig grayVersionConfig;
    @Autowired
    ISequenceNumberService sequenceNumberService;

    @Override
    public TlPaymentLog buildTlPaymentLog(String paymentType, CmCustomerBankcardInfo bank, CustomerRes customerRes,
                                          BigDecimal debtAmount, Date businessDate, PrProductTable product, CommonReq req) throws TxnBizException {
        TlPaymentLog tlPaymentLog = new TlPaymentLog();
        try {
            tlPaymentLog.setId(segmentService.getId(TransBizConstant.TL_PATMENT_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误",e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        tlPaymentLog.setSeqNo(TransBizConstant.PAYMENT_LOG_SEQ_PREFIX+ SeqUtils.getSNByLength(TransBizConstant.PAYMENT_LOG_SEQ_RADOM_LENGTH));//流水号	唯一索引 PL+yyyyMMddHHmmssSSS +13位随机
        tlPaymentLog.setCustomerId(customerRes.getSecondLevel().getCustomerId());//客户id	　
        tlPaymentLog.setTenantId(product.getTenantId());//租户id
        tlPaymentLog.setOrganizationId(customerRes.getSecondLevel().getOrganizationId());//机构号	　	同贷款订单
        tlPaymentLog.setProductId(product.getProductId());//	产品id	　	同贷款订单
        tlPaymentLog.setPaymentType(paymentType);//还款类型	pay = 正常还款 prepay = 提前还款 prepayCurr =提前还当期
        // pretermination = 提前结清  overdue = 逾期还款 cmpspay = 代偿 crtpay 回购
        tlPaymentLog.setChargeType(TransBizConstant.PAYMENT_LOG_CHARGE_TYPE_0);//扣款种类	0=按订单扣款  1=按客户扣款	0
        tlPaymentLog.setJointLoanFlag(product.getAllowJointFlag()); //联合贷标识	0=否 1=是	0
        tlPaymentLog.setIsFullPay(TransBizConstant.YES_FLAG); //	是否足额扣款	0=不足额  1=足额	1
        tlPaymentLog.setAmount(debtAmount);//汇款金额	　	计算出的还款金额
        tlPaymentLog.setCustomerName(customerRes.getFirstLevel().getChineseName());//客户姓名
        tlPaymentLog.setPayerBank(bank.getBankId());//扣款行号
        tlPaymentLog.setPayerBankName(bank.getBankName());//扣款行名称
        tlPaymentLog.setPayerAccount(bank.getCardNumber());//扣款账号	　
        tlPaymentLog.setPayerAccountType(bank.getCardType());//账户类型
        tlPaymentLog.setMobile(customerRes.getSecondLevel().getMobile());//手机
        tlPaymentLog.setRefNo(sequenceNumberService.generateRefNo(Constant.SEQUENCE_LENGTH));
        tlPaymentLog.setDescription(product.getChineseName()+ PaymentUtils.getPaymentTypeName(paymentType));//交易说明	　
        // 产品名称+逾期还款
        tlPaymentLog.setAvailBalance(BigDecimal.ZERO);//余额
        tlPaymentLog.setCurrency(TransBizConstant.CURRENCY_CNY);//币种	　	CNY 人民币
        tlPaymentLog.setEffectDate(DateUtils.formatDate(new Date()));//生效日期	　	当前系统日期
        tlPaymentLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_D); //最终状态 S 成功 F 失败 T 扣款成功，待分配 D 待发起扣款 O
        // 已发起扣款，扣款状态未知，待查询
        tlPaymentLog.setChannel(customerRes.getSecondLevel().getChannel());//渠道id	　	api上送
        tlPaymentLog.setBusinessDate(businessDate);//业务日期	　	当前业务日期
        tlPaymentLog.setCollateDate(businessDate);//对账日期	　	当前业务日期
        tlPaymentLog.setLaunchTime(DateUtils.getBusinessTime(new Date(), businessDate));//交易发起时间	　	当前时间
        tlPaymentLog.setUpdateBy(TransBizConstant.SYS_OPRATE);//操作员
        tlPaymentLog.setRecordVersionNumber(TransBizConstant.INIT_RECORD_VERSION_NUMBER);
        tlPaymentLog.setGrayVersion(grayVersionConfig.getCurrentVersion());
        String thirdChannel = "";
        if (Objects.nonNull(req) && StringUtils.isNotBlank(req.getThirdChannel())) {
            thirdChannel = req.getThirdChannel();
        }
        tlPaymentLog.setThirdChannel(thirdChannel);
        return tlPaymentLog;
    }

    @Override
    public TlPaymentMapping buildTlPaymentMapping(String customerId, String paymentSeqNo, String loanId,
                                                 String tenantId) throws TxnBizException{
        TlPaymentMapping tlPaymentMapping = new TlPaymentMapping();
        try {
            tlPaymentMapping.setId(segmentService.getId(TransBizConstant.TL_PAYMENT_MAPPING_LOG_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误",e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }
        tlPaymentMapping.setTenantId(tenantId);
        tlPaymentMapping.setCustomerId(customerId);//客户ID
        tlPaymentMapping.setPaymentSeqNo(paymentSeqNo);//还款流水seqNo
        tlPaymentMapping.setLoanId(loanId);//贷款订单
        return tlPaymentMapping;
    }

    @Override
    public TlPaymentLog pay(TlPaymentLog log) throws Exception {
        PrOrganizationTable organization = organizationTableService.findByOrId(log.getOrganizationId(), log.getTenantId());
        Date businessDate = organization.getNextProcessingDate();//机构上 当天日期

        TlPaymentLog updateLog = new TlPaymentLog();
        updateLog.setId(log.getId());
        updateLog.setCustomerId(log.getCustomerId());
        updateLog.setTenantId(log.getTenantId());
        updateLog.setLaunchTime(DateUtils.getBusinessTime(new Date(), businessDate));
        updateLog.setSumStatus(log.getSumStatus());
        updateLog.setAvailBalance(BigDecimal.ZERO);//避免未获取到余额报错

        //只有本行卡，并且非足额扣款才需要查询余额。其他按照原逻辑
        if (BankCardConstant.innerCardFlag(log.getPayerAccount())
                && TransBizConstant.REPAYMENT_TYPE_AUTO.equalsIgnoreCase(log.getPaymentType())
                && log.getIsFullPay().equals(TransBizConstant.NO_FLAG)) {
            String coreRequest17Json = dealGatewayService.buildQuestAvailBalance(log);
            GateWayPredicate<CoreResponse17> core17Pre = () -> innerGatewayService.queryAvailBalance(coreRequest17Json);

            CoreResponse17 res = null;
            try {
                res = core17Pre.getRes(core17Pre);
            } catch (Exception e) {
                logger.error("调用API本行卡可用余额异常", e);
            }

            if (res != null) {
                // 账户实际余额
                BigDecimal acctActualBal19 = res.getAcctActualBal19();
                if (Objects.isNull(acctActualBal19)) {
                    acctActualBal19 = BigDecimal.ZERO;
                }
                if (acctActualBal19.compareTo(BigDecimal.ZERO) <= 0) {
                    updateLog.setReturnMsg("账户余额不足");
                    updateLog.setAvailBalance(acctActualBal19);
                } else if (acctActualBal19.compareTo(log.getAmount()) < 0) {
                    //余额不足,按照余额扣款
                    updateLog.setAmount(acctActualBal19);
                    updateLog.setAvailBalance(acctActualBal19);
                    updateLog.setSettleFlag(TransBizConstant.SETTLE_FLAG_0);
                    log.setAmount(acctActualBal19);
                } else {
                    updateLog.setAvailBalance(acctActualBal19);
                }
            }
        }

        //状态为F的不进行扣款
        if (!updateLog.getSumStatus().equals(TransBizConstant.PAYMENT_LOG_SUM_STATUS_F)) {

            String result;
            String busCode;
            String busMsg;
            if (Constant.THIRD_CHANNEL.equalsIgnoreCase(log.getThirdChannel())) {
                String coreRequest16Json = dealGatewayService.buildInterestCompensateReq(log);
                GateWayPredicate<CoreResponse16> core16Pre = () -> innerGatewayService.interestCompensate(coreRequest16Json);
                CoreResponse16 res = null;
                try {
                    res = core16Pre.getRes(core16Pre);
                } catch (Exception e) {
                    logger.error("调用微信还款接口出现异常", e);
                }
                logger.info("ACMT001260用户：{}singleCollection查询结果：{}", log.getCustomerId(), JSONObject.toJSONString(res));
                if (res == null || !CustomerConstant.GATEWAY_BUS_CODE_SUC.equalsIgnoreCase(res.getBusCode())) {
                    updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_O);
                    updateLog.setCompleteTime(DateUtils.getBusinessTime(new Date(), businessDate));
                    return updateLog;
                }
                result = res.getDealState();
                busCode = res.getBusCode();
                busMsg = res.getBusMsg();
            } else {
                //扣款
                String paymentRequest06Json = dealGatewayService.buildCollectReq(log);
                ApiResponse<PaymentResponse06> response = null;
                try {
                    response = innerGatewayService.singleCollection(paymentRequest06Json);
                } catch (Exception e) {
                    e.printStackTrace();
                    logger.error("调用单笔代收接口ACMT001260出现异常", e);
                }
                if (Objects.isNull(response) || Objects.isNull(response.getData())
                        // 内部系统交互失败
                        || TransBizConstant.GATEWAY_SUC != response.getCode()
                        // 行内网关交互失败
                        || !CustomerConstant.GATEWAY_BUS_CODE_SUC.equalsIgnoreCase(response.getData().getBusCode())
                        || response.getData().getBusMsg().contains(TransBizConstant.GATEWAY_CONTENT_TIMEOUT)) {
                    logger.warn("调用还款接口出现异常:{}", JSONObject.toJSONString(response));
                    updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_O);
                    updateLog.setCompleteTime(DateUtils.getBusinessTime(new Date(), businessDate));
                    if (Objects.nonNull(response) && Objects.nonNull(response.getData())) {
                        PaymentResponse06 data = response.getData();
                        updateLog.setReturnCode(data.getBusCode());
                        updateLog.setReturnMsg(data.getBusMsg());
                    }
                    return updateLog;
                }
                PaymentResponse06 res = response.getData();
                logger.info("用户：{}调用还款接口查询结果：{}", log.getCustomerId(), JSONObject.toJSONString(res));
                result = res.getDealResult();
                busCode = res.getBusCode();
                busMsg = res.getBusMsg();
            }

            updateLog.setReturnCode(busCode);
            log.setReturnMsg(busMsg);
            updateLog.setReturnMsg(busMsg);
            updateLog.setReturnStatus(result);
            updateLog.setCompleteTime(DateUtils.getBusinessTime(new Date(), businessDate));
            if (TransBizConstant.GATEWAY_DEAL_SUC.equals(result)) { //成功
                updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_T);
                updateLog.setCollateDate(businessDate);
            } else if (TransBizConstant.GATEWAY_DEAL_FAIL.equals(result)) {//失败
                updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_F);
                updateLog.setCollateDate(businessDate);
            } else { //其他
                updateLog.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_O);
            }
        }
        logger.info("singleCollection用户{}还款批次的结果为{}", log.getCustomerId(), updateLog.getSumStatus());
        //添加短信逻辑 只有拿到终态才需要处理
        if (TransBizConstant.PAYMENT_LOG_SUM_STATUS_F.equals(updateLog.getSumStatus())) {
            log.setSumStatus(TransBizConstant.PAYMENT_LOG_SUM_STATUS_F);
            try {
                iSmsService.paymentProcess(log);
            } catch (Exception e) {
                logger.error("短信发送异常", e);
            }
        }
        return updateLog;
    }

    @Override
    public TxnPage<TlPaymentLogRes> getPaymentWithPage(String channel, String customerId, String tenantId, Integer pageNum, Integer pageSize, String seqNo, String beginDate, String endDate) {
        Page<TlPaymentLog> page = PageHelper.startPage(pageNum, pageSize);
        List<TlPaymentLog> tlDisbursementLogList = extTlPaymentLogMapper.selectByCondSelectivePage(tenantId, channel, customerId, seqNo, beginDate, endDate);
        List<TlPaymentLogRes> res = BeanMapping.copyList(tlDisbursementLogList, TlPaymentLogRes.class);
        return new TxnPage<>(pageNum, pageSize, page.getTotal(), res);
    }

    @Override
    public TlPaymentLogRes getPaymentBySeqNoAndCusId(String tenantId, String seqNo, String customerId) {
        TlPaymentLog tlPaymentLog = extTlPaymentLogMapper.selectPaymnetBySeqNoAndCusId(tenantId, customerId, seqNo);
        TlPaymentLogRes res = BeanMapping.copy(tlPaymentLog, TlPaymentLogRes.class);
        return res;
    }

    /**
     * 获取上次批扣失败客户本次批扣金额
     * @author yhy
     * @date 2023/04/26
     * @param prAutoPaymentTable 渠道产品批扣配置信息
     * @param autoPaymentType 批扣次数
     * @param item  批扣初始化信息
     * @param totalDebt 扣款金额
     * @param businessDate 业务日期
     * @param tlPaymentLog 还款流水信息
     * @return
     */
    @Override
    public TlPaymentLog getAutoPaymentAmount(PrAutoPaymentTable prAutoPaymentTable, int autoPaymentType,
                                           BtAutoPaymentList item, BigDecimal totalDebt, Date businessDate, TlPaymentLog tlPaymentLog) {
        // 本行卡不参与百分比扣款（查询余额扣款）
        // 第一次批扣不做处理 并且 渠道产品批扣配置信息表中有配置批扣失败金额百分比信息
        if (autoPaymentType > 1 && StringUtils.isNotBlank(prAutoPaymentTable.getAutoPaymentAmountPercent()) && !BankCardConstant.innerCardFlag(tlPaymentLog.getPayerAccount())) {
            // 1.获取本次支持的批扣产品信息
            List<String> productIds = new ArrayList<>(Arrays.asList(prAutoPaymentTable.getProductId().split(",")));
            // 2.查询客户该产品列表是否存在上次批扣失败记录
            int count = 0;
            try {
                count = extTlPaymentLogMapper.countCustProudDistinctForBatch(item.getCustomerId(), productIds,
                        TransBizConstant.PAYMENT_LOG_SUM_STATUS_F, TransBizConstant.REPAYMENT_TYPE_AUTO,
                        businessDate, String.valueOf(autoPaymentType - 1));
            } catch (Exception e) {
                logger.error("查询客户上次批扣失败记录异常", e);
            }

            // 若存在批扣失败记录，则对本次批扣金额做百分比换算处理
            if (count > 0) {
                List<String> amountPercents = new ArrayList<>(Arrays.asList(prAutoPaymentTable.getAutoPaymentAmountPercent().split(",")));
                BigDecimal amountPercent = new BigDecimal(amountPercents.get(autoPaymentType - 2)).divide(new BigDecimal(100), CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP);
                // 四舍五入保留2位小数
                totalDebt = totalDebt.multiply(amountPercent).setScale(CommonContants.BIGDECIMAL_SCALE, BigDecimal.ROUND_HALF_UP);
                // 末次扣款金额若大于1000，则取999（用户限额）
                if (amountPercents.size() + 1 == autoPaymentType) {
                    totalDebt = totalDebt.compareTo(new BigDecimal(1000)) >= 0 ? new BigDecimal(999) : totalDebt;
                }
                // 设置非足额扣款标识
                tlPaymentLog.setSettleFlag(TransBizConstant.SETTLE_FLAG_0);
                tlPaymentLog.setIsFullPay(TransBizConstant.NO_FLAG);
            }
        }
        tlPaymentLog.setAmount(totalDebt);
        return tlPaymentLog;
    }
}
